/******************************************************************************/
/* Files to Include                                                           */
/******************************************************************************/

#ifdef __XC32
    #include <xc.h>          /* Defines special funciton registers, CP0 regs  */
#endif

#include <plib.h>            /* Include to use PIC32 peripheral libraries     */
#include <stdint.h>          /* For uint32_t definition                       */
#include <stdbool.h>         /* For true/false definition                     */
#include "dht11.h"            /* variables/params used by user.c               */

#define PIN_DIRECTION TRISDbits.TRISD14
#define PIN_PORT PORTDbits.RD14

#define LED1_DIRECTION TRISDbits.TRISD1
#define LED1_PORT PORTDbits.RD1

/******************************************************************************/
/* User Functions                                                             */
/******************************************************************************/
enum e_ASK_SENSOR_SEQ {
    PIN_OUTPUT = 0,
    LO_18msec,
    HI_20usec,
    ASK_SENSOR_OK
} ;

enum e_WAIT_SENSOR_SEQ {
    PIN_INPUT = 0,
    WAIT_LO,
    LO_80usec,
    HI_80usec,
    WAIT_SENSOR_OK
} ;

enum e_RECV_DATA_SEQ {
    WAIT_BIT_START = 0,
    WAIT_BIT_END,
    WAIT_DATA_END
} ;

unsigned long SEQ_STOP_TIME;
unsigned long BIT_START_TIME;
unsigned int BIT_DURATION_TIME;
unsigned long CURRENT_TIME;

enum e_SEN_STATE SEN_STATE;

enum e_SEN_ERR_STATE_CAUSE ERR_STATE_CAUSE;

enum e_ASK_SENSOR_SEQ ASK_SENSOR_SEQ;

enum e_WAIT_SENSOR_SEQ WAIT_SENSOR_SEQ;

enum e_RECV_DATA_SEQ RECV_DATA_SEQ;

unsigned char DATA_POINTER;
unsigned char DATA_BIT;
unsigned char DATA[5];
unsigned char LAST_DATA[5];
unsigned char LONG_DATA[40];
unsigned char DATA_BYTE_POINTER;
unsigned char DATA_BIT_POINTER;

unsigned int value;
unsigned int delays[100];
unsigned char delay_pointer = 0;

void DHT11Task(void) {
  switch( SEN_STATE ) {
    case SEN_DO_NOTHING:
      break;

    case SEN_ERR_STATE:
      break;

    case SEN_DO_ASK_SENSOR:
      switch ( ASK_SENSOR_SEQ ) {
        case PIN_OUTPUT:
          PORTSetPinsDigitalOut(IOPORT_D,BIT_14);
          PIN_PORT = 0;
          OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_256, 0xFFFF);
          SEQ_STOP_TIME = ReadTimer2() + 6000; // +18 мс
          ASK_SENSOR_SEQ = LO_18msec;
          DATA_POINTER = 0;
          DATA_BYTE_POINTER = 0;
          DATA_BIT_POINTER = 0;
         break;
          
        case LO_18msec:
          if ( ReadTimer2() > SEQ_STOP_TIME  ) {
            SEN_STATE = SEN_DO_WAIT_SENSOR;
            WAIT_SENSOR_SEQ = PIN_INPUT;
            CloseTimer2();
            OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_8, 0xFFFF);
          }
          break;
      }
      break;
    
    case SEN_DO_WAIT_SENSOR:
        CURRENT_TIME = ReadTimer2();
        switch ( WAIT_SENSOR_SEQ ) {
            case PIN_INPUT: 
                PORTSetPinsDigitalIn(IOPORT_D,BIT_14);
                SEQ_STOP_TIME = CURRENT_TIME + 50*10; // ~50 мкс чтобы не ждать низкий уровень вечно
                WAIT_SENSOR_SEQ = WAIT_LO;
                break;
            
            case WAIT_LO: 
                if ( CURRENT_TIME > SEQ_STOP_TIME ) {
                    ERR_STATE_CAUSE = SEN_ERR_NO_LOW_FROM_DHT11;
                    SEN_STATE = SEN_ERR_STATE;
                    CloseTimer2();
                }
                else if ( PIN_PORT == 0 ) {
                    SEQ_STOP_TIME = CURRENT_TIME + 80*10 + 10*10; // +80 мкс + 10 мкс
                    WAIT_SENSOR_SEQ = LO_80usec;
                }
                break;
            
            case LO_80usec:
                if ( PIN_PORT == 1 ) {
                    /*
                    if ( CURRENT_TIME > SEQ_STOP_TIME ) {
                        SEQ_STOP_TIME = CURRENT_TIME + 79*10;
                        WAIT_SENSOR_SEQ = HI_80usec;
                    }
                    else {
                        ERR_STATE_CAUSE = SEN_ERR_TOO_EARLY_HI_FROM_DHT11;
                        SEN_STATE = SEN_ERR_STATE;
                    }
                    */
                    SEQ_STOP_TIME = CURRENT_TIME + 80*10 + 10*10; // +80мкс + 10 мкс
                    WAIT_SENSOR_SEQ = HI_80usec;
                }
                else if ( CURRENT_TIME > SEQ_STOP_TIME ) {
                    ERR_STATE_CAUSE = SEN_ERR_NO_HI_FROM_DHT11;
                    SEN_STATE = SEN_ERR_STATE;
                    CloseTimer2();
                }
                break;
            
            case HI_80usec: 
                if ( PIN_PORT == 0 ) {
                    /*
                    if ( CURRENT_TIME > SEQ_STOP_TIME ) {
                        //WAIT_SENSOR_SEQ = WAIT_SENSOR_OK;
                        SEN_STATE = SEN_DO_RECV_DATA;
                        SEQ_STOP_TIME = CURRENT_TIME + 48*10;
                    }
                    else {
                        ERR_STATE_CAUSE = SEN_ERR_TOO_EARLY_LOW_FROM_DHT11;
                        ERR_STATE_CAUSE = SEQ_STOP_TIME - CURRENT_TIME;
                        SEN_STATE = SEN_ERR_STATE;
                    }
                    */
                    SEQ_STOP_TIME = CURRENT_TIME + 50*10 + 10*10;  // + 50мкс + 10 мкс
                    SEN_STATE = SEN_DO_RECV_DATA;
                    RECV_DATA_SEQ = WAIT_BIT_START;
                }
                else if ( CURRENT_TIME > SEQ_STOP_TIME ) {
                    ERR_STATE_CAUSE = SEN_ERR_NO_LOW2_FROM_DHT11;
                    SEN_STATE = SEN_ERR_STATE;
                    CloseTimer2();
                }
                break;
/*
            case WAIT_SENSOR_OK: 
                SEN_STATE = SEN_DO_RECV_DATA;
                break;
*/
        }
        break;

    case SEN_DO_RECV_DATA:
        CURRENT_TIME = ReadTimer2();
        switch ( RECV_DATA_SEQ ) {
            case WAIT_BIT_START: 
                if ( PIN_PORT == 1 ) {
                    BIT_START_TIME = CURRENT_TIME;
                    SEQ_STOP_TIME = CURRENT_TIME + 80*10; // + 80 мкс
                    RECV_DATA_SEQ = WAIT_BIT_END;
                    /*
                    if ( BIT_START_TIME > SEQ_STOP_TIME ) {
                        SEQ_STOP_TIME = BIT_START_TIME + 90*10;
                        RECV_DATA_SEQ = WAIT_BIT_END;
                    }
                    else {
                        ERR_STATE_CAUSE = SEN_ERR_TOO_EARLY_BIT_HI_FROM_DHT11;
                        SEN_STATE = SEN_ERR_STATE;
                    }
                    */
                }
                else if ( CURRENT_TIME > SEQ_STOP_TIME ) {
                    ERR_STATE_CAUSE = SEN_ERR_NO_BIT_HI_FROM_DHT11;
                    SEN_STATE = SEN_ERR_STATE;
                    CloseTimer2();
                }
                
                break;
            
            case WAIT_BIT_END: 
                if ( PIN_PORT == 0 ) {
                    BIT_DURATION_TIME = CURRENT_TIME - BIT_START_TIME;
                    SEQ_STOP_TIME = CURRENT_TIME + 50*10 + 10*10; // +50мкс + 10 мкс

                    if ( BIT_DURATION_TIME > 65*10  ) { //  Длительность импульма больше 67мкс
                        DATA_BIT = 1;
                    }
                    else if (  BIT_DURATION_TIME < 33*10 ) { // Длительность импульса меньше 29 мкс
                        DATA_BIT = 0;
                    }
                    else {
                        ERR_STATE_CAUSE = SEN_ERR_WRONG_BIT_DURATION_FROM_DHT11;
                        //ERR_STATE_CAUSE = BIT_DURATION_TIME;
                        SEN_STATE = SEN_ERR_STATE;
                        CloseTimer2();
                    }

                    if ( SEN_STATE != SEN_ERR_STATE ) {
                        /*
                        DATA_BYTE_POINTER = DATA_POINTER/8;
                        DATA_BIT_POINTER = DATA_POINTER % 8;
                        DATA[DATA_BYTE_POINTER] = DATA[DATA_BYTE_POINTER] | (DATA_BIT << ( 7 - DATA_BIT_POINTER));
                        RECV_DATA_SEQ = WAIT_BIT_START;
                        */
                        RECV_DATA_SEQ = WAIT_BIT_START;
                        LONG_DATA[DATA_POINTER] = DATA_BIT;
                        ++DATA_POINTER;
                        if ( DATA_POINTER > 39 ) {
                            //RECV_DATA_SEQ = WAIT_DATA_END;
                            RECV_DATA_SEQ = WAIT_DATA_END;
                            //memcpy(LAST_DATA,DATA,5*sizeof(unsigned char));
                        }
                    }
                }

                else if ( CURRENT_TIME > SEQ_STOP_TIME ) {
                    ERR_STATE_CAUSE = SEN_ERR_NO_BIT_LOW_FROM_DHT11;
                    SEN_STATE = SEN_ERR_STATE;
                    CloseTimer2();
                }
                
                break;
 
            case WAIT_DATA_END:
                for ( DATA_POINTER = 0; DATA_POINTER < 40; ++DATA_POINTER) {
                        DATA_BYTE_POINTER = DATA_POINTER/8;
                        DATA_BIT_POINTER = DATA_POINTER % 8;
                        DATA[DATA_BYTE_POINTER] = DATA[DATA_BYTE_POINTER] | (LONG_DATA[DATA_POINTER] << ( 7 - DATA_BIT_POINTER));
                }
                memcpy(LAST_DATA,DATA,5*sizeof(unsigned char));
                SEN_STATE = SEN_DO_NOTHING;
                CloseTimer2();
                break;

        }
        break;
  }
}

void GetLastData( char *data ) {
    data[0] = LAST_DATA[0];
    data[1] = LAST_DATA[1];
    data[2] = LAST_DATA[2];
    data[3] = LAST_DATA[3];
}

void SensorStartAction( void ) {
    DATA_POINTER = 0;
    DATA_BYTE_POINTER = 0;
    DATA_BIT_POINTER = 0;
    memset(DATA,0,5*sizeof(unsigned char));

    ASK_SENSOR_SEQ = PIN_OUTPUT;
    WAIT_SENSOR_SEQ = PIN_INPUT;
    RECV_DATA_SEQ = WAIT_BIT_START;
    SEN_STATE = SEN_DO_ASK_SENSOR;

}

unsigned char SensorGetState( void ) {
    return SEN_STATE;
}

unsigned char SensorGetErrCode( void ) {
    return ERR_STATE_CAUSE;
}

void DHT11Task_v2(void) {
  switch( SEN_STATE ) {
    case SEN_DO_NOTHING:
        break;

    case SEN_ERR_STATE:
        break;

    case SEN_DO_ASK_SENSOR:
          PORTSetPinsDigitalOut(IOPORT_D,BIT_14);
          PIN_PORT = 0;
          OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_256, 0x15F9); // 18мс
          ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2);
        break;

    case SEN_DO_WAIT_SENSOR:
          PORTSetPinsDigitalIn(IOPORT_D,BIT_14);
          CloseTimer2();
          OpenTimer2(T2_ON | T2_SOURCE_INT | T2_PS_1_8, 0xFFFF); // 6553мкс
          ConfigIntTimer2(T2_INT_ON | T2_INT_PRIOR_2);
          mCNOpen(CN_ON | CN_IDLE_CON, CN20_ENABLE, CN_PULLUP_DISABLE_ALL);
          value = mPORTDRead();
          ConfigIntCN(CHANGE_INT_ON | CHANGE_INT_PRI_2);
          SEN_STATE = SEN_DO_RECV_DATA;
        break;

    case SEN_DO_RECV_DATA:
        if ( delay_pointer == 84 ) {
            SEN_STATE = SEN_DO_RECV_COMPLETE;
            mCNClose();
            CloseTimer2();
        }
        break;

    case SEN_DO_RECV_COMPLETE:
        for ( DATA_POINTER = 0; DATA_POINTER < 32; ++DATA_POINTER ) {
            if ( (delays[2*DATA_POINTER+4] - delays[2*DATA_POINTER+3]) < 300 ) {
                LONG_DATA[DATA_POINTER] = 0;
            }
            else {
                LONG_DATA[DATA_POINTER] = 1;
            }
        }
        SEN_STATE = SEN_DO_CALC_DATA;
        break;
    case SEN_DO_CALC_DATA:
        for ( DATA_POINTER = 0; DATA_POINTER < 32; ++DATA_POINTER) {
             DATA_BYTE_POINTER = DATA_POINTER/8;
             DATA_BIT_POINTER = DATA_POINTER % 8;
             DATA[DATA_BYTE_POINTER] = DATA[DATA_BYTE_POINTER] | (LONG_DATA[DATA_POINTER] << ( 7 - DATA_BIT_POINTER));
        }
        memcpy(LAST_DATA,DATA,5*sizeof(unsigned char));
        SEN_STATE = SEN_DO_NOTHING;
        break;
  }
}

void SensorStartRecv( void ) {
    SEN_STATE = SEN_DO_WAIT_SENSOR;
}

void SensorSetErrorState( void ) {
    SEN_STATE = SEN_ERR_STATE;
}

void __ISR(_TIMER_2_VECTOR, ipl2) _Timer2Handler(void){
    // clear the interrupt flag
    mT2ClearIntFlag();

    if ( SensorGetState() == SEN_DO_ASK_SENSOR ) {
        SensorStartRecv();
    }
    if ( SensorGetState() == SEN_DO_WAIT_SENSOR ) {
        SensorSetErrorState();
        CloseTimer2();
        mCNClose();
    }
}

void __ISR(_CHANGE_NOTICE_VECTOR, ipl2) ChangeNotice_Handler(void) {
    mCNClearIntFlag();
    delays[delay_pointer] = ReadTimer2();
    ++delay_pointer;
}